/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package personal.recommender.bayesian;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import personal.recommender.dbi.DBI;
import personal.recommender.dbi.KBI;
import personal.recommender.dbi.LTVI;
import personal.recommender.dbi.VBI;
import personal.recommender.objects.Entity;
import personal.recommender.objects.Parent;
import personal.recommender.objects.User;
import personal.recommender.objects.Video;

/**
 *
 * @author Aya
 */
public class PersonalRecommender {
    
    private static String kbFile = "Knowledge Base.xdsl";
    private static String vbFile = "Video Base.xdsl";
    private static String path = "C:\\Users\\Aya\\RWTH Aachen\\Courses\\Thesis\\Thesis\\Created Networks";
    private static double video_threshold;
    private static double interest_threshold;
    public static final DBI kbi = new KBI();
    public static final VBI vbi = new LTVI();
    
    
    public static void setKBFile(String filename){
        kbFile = filename;
    }
    
    public static void setVBFile(String filename){
        vbFile = filename;
    }
    
    public static void setPath(String p){
        path = p;
    }
    
    public static void setVideoThreshold(double d) {
        video_threshold = d;
    }
    
    public static void setInterestThreshold(double d) {
        interest_threshold = d;
    }
    
    public static List<Video> fetchRecommendations(User u, int n){
        // Set the evidences in the network
        BayesianReader kbr = new BayesianReader(path, vbFile, video_threshold);
        kbr.setEvidence(u.getWatchList(), u.getExplicitInterests(), u.getExplicitDislikes());
        // Read recommendations
        Map<String, Double> nodes = kbr.getRecommendations(n);
        List<Map.Entry<String,Double>> sorted = sortByValues(nodes);
        // Map recommended nodes to Videos
        List<Video> recommendations = new ArrayList<>();
        for (Entry<String, Double> sorted1 : sorted) {
            try {
                Video v = vbi.getVideo(sorted1.getKey());
                recommendations.add(v);
                System.out.println(v.getTitle()+": "+sorted1.getValue());
            } catch(Exception e){
                System.out.println("Video "+sorted1.getKey()+" not found in the database");
            }
        }
        return recommendations;
    }
    
    public static List<Entity> fetchInferredInterests(User u, int n){
        // Set the evidences in the network
        BayesianReader kbr = new BayesianReader(path, vbFile, interest_threshold);
        kbr.setEvidence(u.getWatchList(), u.getExplicitInterests(), u.getExplicitDislikes());
        // Read Interests
        Map<String, Double> nodes = kbr.getImplicitInterests(n);
        List<Map.Entry<String,Double>> sorted = sortByValues(nodes);
        // Map interesting nodes to entities
        List<Entity> interests = new ArrayList<>();
        for (Entry<String, Double> sorted1 : sorted) {
            String node = sorted1.getKey();
            try {
                Entity e = kbi.getEntity(node);
                interests.add(e);
                System.out.println(e.getName()+ ": " + sorted1.getValue());
            }catch(Exception e){
                System.out.println("Entity "+node+" not found in the database");
            }
        }
        return interests;
    }
    
    public static void buildKB(String name){
        BayesianBuilder kbb = new BayesianBuilder(path, name);
        // Load all nodes
        List<Entity> entities = kbi.getAllEntities();
        for(Entity entity: entities){
            kbb.createNode(entity);
        }
        // Create connections between the nodes
        try {
            for(Entity entity: entities){
                List<Parent> parents = kbi.getParentsOf(entity);
                kbb.createArc(entity, parents);
            }
        } catch (Exception ex) {
            System.out.println("Detected a flaw in the knowledge data, please review. \n Details: "+ex.getMessage());
            Logger.getLogger(PersonalRecommender.class.getName()).log(Level.SEVERE, null, ex);
        }
        // Write the network to a file
        try {
            kbb.saveKBNetworkAs(kbFile); 
        } catch(IOException e){
            System.out.println("Error writing the knowledge file");
        }
    }
    
    public static void buildVB(String name){
        BayesianBuilder vbb = new BayesianBuilder(path, name, kbFile);
        // Load all videos and connect them to the KB
        List<Video> videos = vbi.getAllVideos();
        for(Video video: videos){
            vbb.createNode(video);
            List<Parent> parents = vbi.getAnnotations(video.getId());
            vbb.createArc(video, parents);
        }
        // Write the network to a file
        try {
            vbb.saveKBNetworkAs(vbFile);
        } catch(IOException e){
            System.out.println("Error writing the video file");
        }
    }

    public static List<Video> getVideosWithTopic(String topic) {
        return vbi.getVideosWithTopic(topic);
    }
    
    private static <K extends Comparable,V extends Comparable> List<Map.Entry<K,V>> 
        sortByValues(Map<K,V> map){
        
            List<Map.Entry<K,V>> entries = new LinkedList<>(map.entrySet());
            Collections.sort(entries, new Comparator<Map.Entry<K,V>>() {
                @Override
                public int compare(Entry<K, V> o1, Entry<K, V> o2) {
                    return o2.getValue().compareTo(o1.getValue());
                }
            });
            return entries;
    }

    public static void getAnnotationsIn(int id) {
        List<Parent> parents = vbi.getAnnotations(id);
        for(Parent p: parents){
            try {
                System.out.println(kbi.getEntity(p.getIdentifier()).getName()+" - "+p.getProbability());
            } catch(Exception e){
                
            }
        }
    }
}
